/*
 * RobotFrame.java -
 * Copyright (c) 2005 Carmine Lia
 * e-mail:      carmine.lia@libero.it
 * web-address: http://www.intermedia.sa.it/lia

 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
package javax.robotics.swing;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;

import javax.Robotics.vecmath.Color3f;
import javax.Robotics.vecmath.Point3d;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.robotics.engine.robots.Robot3D;
import javax.robotics.image.ImageDisplayer;
import javax.robotics.j3d.OffScreenCanvas3D;
import javax.robotics.j3d.Robot3DSceneGraph;
import javax.robotics.j3d.RobotCanvas3D;
import javax.robotics.xml.XmlRobot;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.ViewingPlatform;
/**
 * This class helps to embed Java3D scene and Robot3D in java windows.
 * <p>
 * Example</br>
 * 
 * <pre>
 * 
 *  
 *   public class MyFrame3D extends RobotFrame
 *   {
 *   ...
 *        MyFrame3D(String title)
 *        {
 *            ...
 *            Robot3D robot  = new DHRobot3D(njoints, init);
 *            addRobotToDefaultConfiguration(robot);
 *            setVisible(true);
 *        }
 *   ...
 *    public static void main(String[] args)
 *    {
 *        new MyFrame3D(&quot;Window title&quot;);
 *    }
 *  }
 *   
 *  
 * </pre>
 * 
 * </p>
 * 
 * @author <a href="http://www.intermedia.sa.it/lia/">Carmine Lia</a>
 * @since 1.0.3
 */
public class RobotFrame extends JFrame implements KeyListener
{

    /**
     * 
     */
    private static final long serialVersionUID = 3256727294520342068L;
    
    private static final String strLineSeparator = "line.separator";     
    private final String strNewLine =  System.getProperty(strLineSeparator);
    
  //  private final ClassLoader cl = this.getClass().getClassLoader();
    
    private String  robotName;
    private RobotCanvas3D canvas3D;
    private SimpleUniverse simpleU;
    private ViewingPlatform vP;
    private OrbitBehavior orbit;
    private Robot3DSceneGraph objRoot;
    private Background background;
    private OffScreenCanvas3D offScreenCanvas3D;
    private int width;
    private int height;

    /**
     * Constructor of a 600x600 Java3D window.
     * <p>
     * You can move the View around a point of interest when the mouse is
     * dragged with a mouse button pressed. Includes rotation, zoom, and
     * translation actions.
     * </p>
     * <p>
     * The rotate action rotates the ViewPlatform around the point of interest
     * when the mouse is moved with the main mouse button pressed. The rotation
     * is in the direction of the mouse movement, with a default rotation of
     * 0.01 radians for each pixel of mouse movement.
     * </p>
     * <p>
     * The zoom action moves the ViewPlatform closer to or further from the
     * point of interest when the mouse is moved with the middle mouse button
     * pressed (or Alt-main mouse button on systems without a middle mouse
     * button).
     * </p>
     * <p>
     * The translate action translates the ViewPlatform when the mouse is moved
     * with the right mouse button pressed (Shift-main mouse button on systems
     * without a right mouse button).
     * </p>
     * <p>
     * The command CTRL-P copy the Canvas3D as an image that could be printed.
     * </p>
     * <p>
     * The command CTRL-H show an help message.
     * </p>
     * 
     * @throws HeadlessException
     */
    public RobotFrame() throws HeadlessException
    {
        this("Robot Frame", 600, 600);
    }
    /**
     * Constructor of a 600x600 Java3D window.
     * 
     * @param title
     *            the window title.
     * @throws HeadlessException
     * @see #RobotFrame()
     */
    public RobotFrame(String title) throws HeadlessException
    {
        this(title, 600, 600);
    }

    /**
     * Constructor of a Java3D window.
     * 
     * @param title
     *            the window title.
     * @param width
     *            the window width.
     * @param height
     *            the window heigth.
     * @throws HeadlessException
     * @throws InvocationTargetException 
     * @throws IllegalAccessException 
     * @throws NoSuchMethodException 
     * @throws IllegalArgumentException 
     * @throws SecurityException 
     * @see #RobotFrame()
     */
    public RobotFrame(String title, int width, int height)
            throws HeadlessException
    {
       
        super(title);
        this.width = width;
        this.height = height;
        this.robotName = "Robot3D";
        
        
        init();
    }

    /**
     * Creates the default scene 3D and adds to it the Robot3D object.
     * 
     * @param robot
     *            the Robot3D
     */
    public void addRobotToDefaultConfiguration(Robot3D robot)
    {
        addRobotToDefaultConfiguration(robot, null);
    }

    /**
     * Creates the default scene 3D and adds to it the Robot3D object.
     * 
     * @param robot
     *            the Robot3D
     * @param bh
     *            the Behavior class to add.
     */
    public void addRobotToDefaultConfiguration(Robot3D robot, Behavior bh)
    {
        final XmlRobot conf = robot.getRobotConfiguration();
        robotName = (conf == null)? "Robot":conf.getName();
       
        // create objRoot
        objRoot = new Robot3DSceneGraph(bh);
        background = objRoot.getBackground();
        
        // adding 3D model of robot
        objRoot.addChild(robot.getModel3D());

        // ottimizzazione.
        objRoot.compile();

        simpleU.addBranchGraph(objRoot);
    }
    /**
     * Gets the SimpleUniverse object so that you can add to it your own scene
     * 3D.
     * 
     * @return the simple universe.
     */
    final public SimpleUniverse getSimpleUniverse()
    {
        return simpleU;
    }

    /**
     * Gets the root BranchGroup of 3D scene.
     * 
     * @return the root branchgroup
     */
    final public BranchGroup get3DRootBranch()
    {
        return objRoot;
    }

    public void keyTyped(KeyEvent e)
    {

    }

    public void keyPressed(KeyEvent e)
    {

        // System.out.println(KeyEvent.VK_P+"\n"+e.isControlDown()+"\n"+e.getKeyCode());
        if((e.getKeyCode() == KeyEvent.VK_P) && e.isControlDown())
        {
            final Color3f origColor = new Color3f();
            background.getColor(origColor);
            background.setColor(1.0f, 1.0f, 1.0f);
            export();
            background.setColor(origColor);
        }
        if((e.getKeyCode() == KeyEvent.VK_E) && e.isControlDown())
        {
            export();
        }
        if((e.getKeyCode() == KeyEvent.VK_H) && e.isControlDown())
           showHelpMessage();
        
       
    }

    public void keyReleased(KeyEvent e)
    {

    }

    private void init()
    {
        canvas3D = new RobotCanvas3D();
        canvas3D.addKeyListener(this);
        canvas3D.setPreferredSize(new Dimension(width, height));
        // creazione del simple universe
        simpleU = new SimpleUniverse(canvas3D);

        // creazione del Canvas3D off-screen
        offScreenCanvas3D = canvas3D.getOffScreenCanvas3D();
        simpleU.getViewer().getView().addCanvas3D(offScreenCanvas3D);

        // creazione della viewing platform
        vP = simpleU.getViewingPlatform();
        vP.setNominalViewingTransform();

        // aggiunta della possibilit? di ruotare, traslare, zoom della scena col
        // mouse
        orbit = new OrbitBehavior(canvas3D, OrbitBehavior.REVERSE_ALL);
        orbit.setSchedulingBounds(new BoundingSphere(
                new Point3d(0.0, 0.0, 0.0), 1.0));
        vP.setViewPlatformBehavior(orbit);

       
        // setting this frame
   //     setPreferredSize(new Dimension(width, height));
        setLayout(new BorderLayout());
        add(canvas3D, BorderLayout.CENTER);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // pack();
    }

    private final void showHelpMessage()
    {
        JOptionPane
        .showMessageDialog(
                null,
                "To Rotate the scene move the mouse with the main mouse button pressed" + strNewLine 
                        + "To Zoom the scene move the mouse with the middle mouse button pressed" + strNewLine  
                        + "(or Alt-main mouse button on systems without a middle mouse button)" + strNewLine 
                        + "To Translate the scene move the mouse with the right mouse button pressed" + strNewLine 
                        + "(Shift-main mouse button on systems without a right mouse button)." + strNewLine
                        + "Export the scene for printing press CTRL+P"+ strNewLine
                        + "Export the scene as image press CTRL+E",
                "Help", JOptionPane.INFORMATION_MESSAGE);

    }

    private final void export()
    {
        final  Dimension dim = canvas3D.getSize();
        final BufferedImage bImage = offScreenCanvas3D.doRender(dim.width,
                dim.height);
        new ImageDisplayer(bImage, robotName);
    }
}
